import { Component, Vue } from 'vue-property-decorator'
import mapboxgl from 'mapbox-gl'
import 'mapbox-gl/dist/mapbox-gl.css'
import CoordinatesControl from '@/components/knowledge-gis/map-packages/coordinates-control'
import CustomNavigationControl from '@/components/knowledge-gis/map-packages/custom-navigation-control'
import { knowledgeGisMapResetByLayers } from '@/components/knowledge-gis/map-packages/map-utils'
import elementResizeDetectorMaker from 'element-resize-detector'
import { debounce } from 'lodash'
import { getMapTilesByMapTypeAndStyle } from '@/components/knowledge-gis/map-packages/map-tiles'
import * as turf from '@turf/turf'

@Component({})
export default class KnowledgeGisMapMixin extends Vue {
  public mapBox: any = '' // 实例化地图
  // mapbox popup
  public mapboxPopup: any = new mapboxgl.Popup({
    closeButton: false,
    closeOnClick: false,
  })

  /**
   * 实例化地图
   * @param mapType 地图类型
   * @param tileStyle 地图瓦片类型
   * @param idName 容器id
   */
  public initMapBoxMixin(
    mapType: number = 1,
    tileStyle: number = 1,
    idName: string = 'map'
  ) {
    this.mapBox = new mapboxgl.Map({
      container: idName, // container ID
      style: getMapTilesByMapTypeAndStyle(mapType, tileStyle), // style URL
      bounds: [
        [73.536163, 53.558094],
        [135.084259, 7.397329],
      ],
      center: [106.1157366, 37.95462],
      zoom: 4, // starting zoom
      minZoom: 1.5,
      maxZoom: 18.9,
      dragPan: true,
      attributionControl: false,
      // antialias: true,  // 抗锯齿
      // logoPosition: 'top-right',
      // renderWorldCopies: false, // 地图缩小时将渲染多个全局地图的副本
    })
  }

  /**
   * 添加经纬度坐标位置控件 （自定义）
   */
  public addCoordinatesControlMixin() {
    if (!this.mapBox) {
      return
    }
    const coordinatesControl: any = new CoordinatesControl({
      decimal: 2, // 经纬度精度
    })
    this.mapBox.addControl(coordinatesControl, 'bottom-left')
  }

  // mapbox gl 比例尺
  public mapScale = new mapboxgl.ScaleControl({
    maxWidth: 100, // 比例尺控制的最大长度,默认100，以像素为单位
    unit: 'metric', // 单位，分为 'imperial', 'metric','nautical' 三种类型，默认为 'metric'
  })

  /**
   * 添加 / 移除 比例尺
   * @param value 添加 - true / 移除 - false
   */
  public addOrRemoveScaleControlMixin(value: boolean) {
    if (!this.mapBox) {
      return
    }
    // 添加导航控件，控件的位置包括 'top-left', 'top-right','bottom-left' ,'bottom-right' 四种，默认为 'bottom-left'
    if (value) {
      this.mapBox.addControl(this.mapScale, 'bottom-left')
    } else {
      this.mapBox.removeControl(this.mapScale)
    }
  }

  /**
   * 添加地图导航控件 （自定义）
   */
  public addNavigationControlMixin(resetMap: any) {
    if (!this.mapBox) {
      return
    }
    const navigationControl: any = new CustomNavigationControl({
      showOverview: false,
      showDragPan: true,
      showZoom: true,
      showReset: true,
      gisBase: this,
      resetMap,
      // toggleOverview: this.callBackEvents?.toggleOverview
    })
    this.mapBox.addControl(navigationControl, 'top-left')
  }

  /**
   * 地图复位
   * @param layers
   * @param layerData
   */
  public resetMapMixin(layers: any, layerData: any) {
    if (!this.mapBox) {
      return
    }
    const fitBounds: any = knowledgeGisMapResetByLayers(layers, layerData)
    try {
      this.mapBoxFitBoundsMixin(fitBounds)
    } catch (error) {
      console.error(error)
    }
  }

  /**
   * 根据两角坐标设定边界适应窗口
   * @param bounds
   */
  public mapBoxFitBoundsMixin(bounds: any[]) {
    this.mapBox.fitBounds(bounds, { padding: 50 })
  }

  /**
   * 画布尺寸调整
   */
  public mapResizeMixin() {
    const rootErd = elementResizeDetectorMaker()
    const mapBox = this.$refs.mapBox as HTMLElement
    rootErd.listenTo(mapBox, this.mapBoxResizeDebounce)
    this.$once('hook:beforeDestroy', () => {
      rootErd.removeAllListeners(mapBox)
    })
  }
  // 防抖
  public mapBoxResizeDebounce = debounce(() => this._mapBoxResize(), 500)
  private _mapBoxResize() {
    this.mapBox.resize()
  }

  /**
   * 地图缩放
   * @param type
   */
  public mapZoomMixin({ type }: { type: string }) {
    if (type === 'zoomIn') {
      this.mapBox.zoomIn()
    } else {
      this.mapBox.zoomOut()
    }
  }

  /**
   * 初始化 添加空图层，占据最底层
   */
  public initAddEmptyMixin() {
    const emptyLayerExist = this.mapBox.getLayer('base-empty-layer')
    if (!emptyLayerExist) {
      const layerInfo: any = {
        id: 'base-empty-layer',
        type: 'fill',
        source: {
          type: 'geojson',
          data: null,
        },
      }
      this.mapBox.addLayer(layerInfo)
    }
  }

  /**
   * 添加点图层
   * @param points
   * @param layerId
   * @param beforeId
   */
  public addPointMixin(points: any, layerId: any, beforeId: string) {
    const sourceId: string = `source-${layerId}`
    this.mapBox.addSource(sourceId, {
      type: 'geojson',
      data: points.geojson,
      promoteId: 'id', // 地图中id不能直接用中文，如果需要用中文，只能通过promoteId去properties中提升上来
    })
    // 将点添加到一个图层中，在地图中显示
    const layerIdString: string = String(layerId)
    const layerInfo: any = {
      id: layerIdString,
      type: 'circle',
      renderingMode: '2d',
      source: sourceId,
      // 设置绘制参数
      paint: {
        'circle-radius': [
          'interpolate',
          ['linear'],
          ['zoom'],
          // zoom is 5 (or less) -> circle radius will be 1px ,getZoom()
          8,
          5,
          // zoom is 10 (or greater) -> circle radius will be 5px
          10,
          8,
        ],
        // 'circle-color': '#ff0000', // 设置点的填充颜色
        'circle-color': [
          'case',
          ['boolean', ['feature-state', 'hover'], false],
          '#aed495',
          ['boolean', ['feature-state', 'select'], false],
          '#16A37E ',
          //  prepare for entity different color
          [
            'match',
            ['get', 'color'],
            'brown',
            '#B15928',

            'yellow',
            '#FBC94B',

            'sienna',
            '#EF7C52',

            'red',
            '#E53E2B',

            'magenta',
            '#CC69D9',

            'slateBlue',
            '#7751FF',

            'violet',
            '#7A88F2',

            'cornflower',
            '#8DD3C7',

            'monte',
            '#9BCA63',

            'meadow',
            '#16A37E',

            'lynch',
            '#6E80A2',

            'silver',
            '#ABABAB',

            /* other */
            '#000',
          ],
        ],
        'circle-opacity': 1,
      },
    }
    if (beforeId) {
      this.mapBox.addLayer(layerInfo, beforeId)
    } else {
      this.mapBox.addLayer(layerInfo)
    }
  }

  /**
   * 添加线图层
   * @param lines
   * @param layerId
   * @param beforeId
   * @param withArrow
   */
  public addLineMixin(
    lines: any,
    layerId: number,
    beforeId: string,
    withArrow: boolean = false
  ) {
    const sourceId: string = `source-${layerId}`
    this.mapBox.addSource(sourceId, {
      type: 'geojson',
      data: lines.geojson,
      promoteId: 'id',
    })
    // 将点添加到一个图层中，在地图中显示
    const layerIdString: string = String(layerId)
    const layerInfo: any = {
      id: layerIdString,
      type: 'line',
      renderingMode: '2d',
      source: sourceId,
      // 设置绘制参数
      paint: {
        // 'line-color': '#345678',
        'line-color': [
          'case',
          ['boolean', ['feature-state', 'hover'], false],
          '#aed495',
          ['boolean', ['feature-state', 'select'], false],
          '#16A37E ',
          //  prepare for entity different color
          [
            'match',
            ['get', 'color'],
            'brown',
            '#B15928',

            'yellow',
            '#FBC94B',

            'sienna',
            '#EF7C52',

            'red',
            '#E53E2B',

            'magenta',
            '#CC69D9',

            'slateBlue',
            '#7751FF',

            'violet',
            '#7A88F2',

            'cornflower',
            '#8DD3C7',

            'monte',
            '#9BCA63',

            'meadow',
            '#16A37E',

            'lynch',
            '#6E80A2',

            'silver',
            '#ABABAB',
            /* other */
            '#345678',
          ],
        ],
        'line-width': 3,
        'line-opacity': 1,
      },
    }
    if (beforeId) {
      this.mapBox.addLayer(layerInfo, beforeId)
    } else {
      this.mapBox.addLayer(layerInfo)
    }
    console.log('withArrow', withArrow)
    // if (withArrow) {
    //   this.addArrowToLineLayerByIdMixin(layerId, lines.geojson)
    // }
  }

  /**
   * 计算单条线的箭头位置及角度
   * @param coordinates
   */
  public calcPointByLineMixin(coordinates: any[]) {
    const coordinatesLength: number = coordinates.length
    const beforePoint: any = coordinates[coordinatesLength - 2]
    const end: any = coordinates[coordinatesLength - 1]
    const bearing = turf.bearing(beforePoint, end)
    return {
      type: 'Feature',
      properties: {
        bearing,
      },
      geometry: {
        type: 'Point',
        coordinates: end,
      },
    }
  }

  /**
   * 根据线 geoJson 生成箭头 geoJson
   * @param geoJson
   */
  public generateArrowGeoJsonMixin(geoJson: any) {
    const arrowFeatures: any = []
    // 线数据
    geoJson.features.forEach((feature: any) => {
      const { coordinates, type } = feature.geometry
      // 多线
      if (type === 'MultiLineString') {
        coordinates.forEach((line: any) => {
          arrowFeatures.push(this.calcPointByLineMixin(line))
        })
      } else if (type === 'LineString') {
        arrowFeatures.push(this.calcPointByLineMixin(coordinates))
      }
    })
    return {
      type: 'FeatureCollection',
      features: arrowFeatures,
    }
  }

  /**
   * 给 线图层 添加箭头
   * @param layerId
   * @param geoJson
   */
  public addArrowToLineLayerByIdMixin(layerId: number, geoJson: any) {
    const arrowGeoJson: any = this.generateArrowGeoJsonMixin(geoJson)
    const arrowSourceId: string = `source-arrow-${layerId}`
    this.mapBox.addSource(arrowSourceId, {
      type: 'geojson',
      data: arrowGeoJson,
    })
    this.mapBox.loadImage(
      '/img/gis/line-arrow.png',
      (error: any, image: any) => {
        if (error) {
          throw error
        }
        const imageName = Math.random().toString(36).slice(-8)
        this.mapBox.addImage(imageName, image)
        this.mapBox.addLayer(
          {
            id: `arrow-${layerId}`,
            source: arrowSourceId,
            type: 'symbol',
            layout: {
              'icon-image': imageName,
              'icon-rotate': ['get', 'bearing'],
              'icon-rotation-alignment': 'map',
              'icon-allow-overlap': true,
              'icon-ignore-placement': true,
              'icon-size': [
                'interpolate',
                ['linear'],
                ['zoom'],
                11,
                0.3,
                13,
                0.7,
              ],
            },
          },
          String(layerId)
        )
      }
    )
  }

  /**
   * 添加面图层
   * @param polygon
   * @param layerId
   * @param beforeId
   */
  public addPolygonMixin(polygon: any, layerId: number, beforeId: string) {
    const sourceId: string = `source-${layerId}`
    this.mapBox.addSource(sourceId, {
      type: 'geojson',
      data: polygon.geojson,
      promoteId: 'id',
    })
    // 将多边形添加到一个图层中，在地图中显示
    const layerIdString: string = String(layerId)
    const layerInfo: any = {
      id: layerIdString,
      type: 'fill',
      source: sourceId,
      // 设置绘制参数
      paint: {
        // 'fill-color': '#467be8',
        // 'fill-outline-color': '#1e49f8',
        'fill-color': [
          'case',
          ['boolean', ['feature-state', 'hover'], false],
          '#aed495',
          ['boolean', ['feature-state', 'select'], false],
          '#16A37E ',
          //  prepare for entity different color
          [
            'match',
            ['get', 'color'],
            'brown',
            '#B15928',

            'yellow',
            '#FBC94B',

            'sienna',
            '#EF7C52',

            'red',
            '#E53E2B',

            'magenta',
            '#CC69D9',

            'slateBlue',
            '#7751FF',

            'violet',
            '#7A88F2',

            'cornflower',
            '#8DD3C7',

            'monte',
            '#9BCA63',

            'meadow',
            '#16A37E',

            'lynch',
            '#6E80A2',

            'silver',
            '#ABABAB',
            /* other */
            '#467be8',
          ],
        ],
        'fill-outline-color': [
          'case',
          ['boolean', ['feature-state', 'hover'], false],
          '#aed495',
          ['boolean', ['feature-state', 'select'], false],
          '#16A37E ',
          '#1e49f8',
        ],
        // 设置透明度
        'fill-opacity': 0.6,
      },
    }
    if (beforeId) {
      this.mapBox.addLayer(layerInfo, beforeId)
    } else {
      this.mapBox.addLayer(layerInfo)
    }
  }

  /**
   * 添加 label 图层
   * @param layerId
   * @param labelName 显示label 的字段
   */
  public addLabelMixin(layerId: number, labelName: string = 'label') {
    const sourceId: string = `source-${layerId}`
    const beforeId: string = String(layerId)
    // 将 label 添加到一个图层中，在地图中显示
    const layerIdString: string = `label-${layerId}`
    const layerInfo: any = {
      id: layerIdString,
      type: 'symbol',
      source: sourceId,
      layout: {
        'text-field': ['get', labelName],
        'text-font': ['Open Sans Regular,Arial Unicode MS Regular'],
        'text-offset': [0, 0.6],
        'text-anchor': 'top',
        'text-size': 12,
      },
    }
    if (beforeId) {
      this.mapBox.addLayer(layerInfo, beforeId)
    } else {
      this.mapBox.addLayer(layerInfo)
    }
  }

  /**
   * 删除图层 通过图层管理删除
   * @param layersId
   */
  public deleteLayersMixin(layersId: any[]) {
    layersId.forEach((id: any) => {
      if (this.mapBox.getLayer(String(id))) {
        this.mapBox.removeLayer(String(id))
      }
      if (this.mapBox.getSource(`source-${id}`)) {
        this.mapBox.removeSource(`source-${id}`)
      }
    })
  }

  /**
   * 修改图层属性 显示隐藏
   * @param layerId
   * @param visible
   */
  public editLayerVisiblePropertyByLayerId(layerId: string, visible: number) {
    const currentLayerExit: any = this.mapBox.getLayer(layerId)
    if (currentLayerExit) {
      const value: string = visible === 0 ? 'none' : 'visible'
      this.mapBox.setLayoutProperty(layerId, 'visibility', value)
    }
  }

  /**
   * 删除图层
   * @param deleteLayerIds
   */
  public deleteLayerByIds(deleteLayerIds: any[]) {
    deleteLayerIds.forEach((id: any) => {
      // label删除图层
      if (this.mapBox.getLayer(`label-${id}`)) {
        this.mapBox.removeLayer(`label-${id}`)
      }
      // 删除图层
      if (this.mapBox.getLayer(String(id))) {
        this.mapBox.removeLayer(String(id))
      }
      // 删除图层源数据
      if (this.mapBox.getSource(`source-${id}`)) {
        this.mapBox.removeSource(`source-${id}`)
      }
    })
  }

  /**
   * 删除图层对应的箭头 (线图层)
   * @param deleteLayerId
   */
  public deleteLayerArrowByIds(deleteLayerId: any) {
    // 删除图层
    if (this.mapBox.getLayer(`arrow-${deleteLayerId}`)) {
      this.mapBox.removeLayer(`arrow-${deleteLayerId}`)
    }
    // 删除图层源数据
    if (this.mapBox.getSource(`source-arrow-${deleteLayerId}`)) {
      this.mapBox.removeSource(`source-arrow-${deleteLayerId}`)
    }
  }
}
